﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace EssionTask
{
    public class TaskChain
    {
        public List<Task<Dictionary<string, object>>> Tasks;// = new List<Task<dynamic>>();
        public event EventHandler<List<Task<Dictionary<string, object>>>> ExecuteComplete;
        public event Action<TaskChain, AggregateException> ExecuteError;
        public TaskChain()
        {
            Tasks = new List<Task<Dictionary<string, object>>>();
        }
        CancellationTokenSource cts = new CancellationTokenSource();
        Progress<double> progress = new Progress<double>();
        public void Execute()
        {

            ThreadPool.QueueUserWorkItem(o =>
            {

                if (Tasks.Count == 0)
                {
                    return;
                }
                progress.ProgressChanged += progress_ProgressChanged;
                for (int i = 0; i < this.Tasks.Count; i++)
                {
                    if (i < Tasks.Count - 1)//除了最后一个任务外.
                    {
                        int i1 = i;

                        Tasks[i].ContinueWith((t) =>
                        {
                            int ti = i;
                            (progress as IProgress<double>).Report((double)(ti + 1) / (this.Tasks.Count));
                            Tasks[i1 + 1].Start();
                        }, TaskContinuationOptions.AttachedToParent | TaskContinuationOptions.OnlyOnRanToCompletion);

                    }
                }
                if (Tasks.Count > 0)
                {
                    Tasks[0].Start();

                }
                try
                {
                    Task.WaitAll(Tasks.ToArray());
                }
                catch (AggregateException ex)
                {
                    if (ExecuteError != null)
                    {
                        ExecuteError(this, ex);
                    }

                }

                if (ExecuteComplete != null)
                {
                    ExecuteComplete(this, Tasks);
                }
            });

        }

        void progress_ProgressChanged(object sender, double e)
        {
            OnProgressChanged(this, e);
        }

        private void OnProgressChanged(TaskChain taskChain, double e)
        {
            if (TaskProgressChanged != null)
            {
                TaskProgressChanged(e);
            }
        }

        public event Action<double> TaskProgressChanged;

        public void AddTask(Func<Dictionary<string, object>> task)
        {
            //            object state = null;
            //
            //            if (this.Tasks.Count > 1)
            //            {
            //                state = this.Tasks[Tasks.Count - 1].Result; 
            //            }
            var t = new Task<Dictionary<string, object>>(
                  task
                  );
            this.Tasks.Add(t);

        }
        //        public void Stop()
        //        {
        //            cts.Cancel();
        //        }
    }
}
